package citylife.geotools.demo;

import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.util.Arrays;
import java.util.Collection;
import java.util.concurrent.CountDownLatch;

import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.tile.Tile;
import org.geotools.tile.TileService;
import org.geotools.tile.util.AsyncTileLayer;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.operation.TransformException;

public class Class7AsyncTileLayer extends AsyncTileLayer {

  private CountDownLatch countDownLatch;

  public Class7AsyncTileLayer(TileService service) {
    super(service);
  }

  @Override
  protected void renderTiles(Collection<Tile> tiles, Graphics2D g2d, ReferencedEnvelope viewportExtent, AffineTransform worldToImageTransform) {

    this.countDownLatch = new CountDownLatch(tiles.size());

    localRenderTiles(tiles, g2d, viewportExtent, worldToImageTransform);
    try {
      this.countDownLatch.await();
    } catch (InterruptedException ie) {
      java.util.logging.Logger.getGlobal().log(java.util.logging.Level.INFO, "", ie);
    }
    this.countDownLatch = null;
  }

  @Override
  protected void renderTile(final Tile tile, final Graphics2D g2d, final double[] points) {

    Runnable r = () -> {
      BufferedImage img = getTileImage(tile);

      g2d.drawImage(img, (int) points[0], (int) points[1], (int) Math.ceil(points[2] - points[0]), (int) Math.ceil(points[3] - points[1]), null);

      countDownLatch.countDown();
      System.out.println("renderTile[" + tile.getId() + "] points : " + Arrays.toString(points));
      System.out.println("renderTile[" + tile.getId() + "] img: " + img);
      System.out.println("renderTile[" + tile.getId() + "] w: " + (int) Math.ceil(points[2] - points[0]));
      System.out.println("renderTile[" + tile.getId() + "] h: " + (int) Math.ceil(points[3] - points[1]));
    };
    new Thread(r).start();

    try {
      Thread.sleep(10);
    } catch (InterruptedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }

  private final String EPSG_FOR_CHINA_2000 = "EPSG4490";

  private final String EPSG_FOR_WGS_84 = "EPSG4326";

  protected void localRenderTiles(Collection<Tile> tiles, Graphics2D g2d, ReferencedEnvelope viewportExtent, AffineTransform worldToImageTransform) {

    g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);

    // CGCS2000 与 WGS84 几乎一致。在不涉及高精度作业时，无需转换。（扁率不同导致时间、速度场的改算）
    String nativeCrsId = tiles.stream().findFirst().get().getExtent().getCoordinateReferenceSystem().getIdentifiers().stream().findFirst().get().getCodeSpace() + tiles.stream().findFirst().get()
        .getExtent().getCoordinateReferenceSystem().getIdentifiers().stream().findFirst().get().getCode();
    String viewCrsId = viewportExtent.getCoordinateReferenceSystem().getIdentifiers().stream().findFirst().get().getCodeSpace() + viewportExtent.getCoordinateReferenceSystem().getIdentifiers()
        .stream().findFirst().get().getCode();
    boolean is2000To84 = EPSG_FOR_CHINA_2000.equals(nativeCrsId) && EPSG_FOR_WGS_84.equals(viewCrsId);

    for (Tile tile : tiles) {
      String opmsg = "tileid:%s maxX:%.2f maxY:%.2f minX:%.2f minY:%.2f ";
      ReferencedEnvelope nativeTileEnvelope = tile.getExtent();
      System.out.println(opmsg.formatted(tile.getId(), nativeTileEnvelope.getMaxX(), nativeTileEnvelope.getMaxY(), nativeTileEnvelope.getMinX(), nativeTileEnvelope.getMinY()));

      ReferencedEnvelope tileEnvViewport;
      try {
        if (is2000To84) {
          // CGCS2000 到 WGS84的转换导致坐标部分异常，所以不转了
          tileEnvViewport = nativeTileEnvelope;
        } else {
          tileEnvViewport = nativeTileEnvelope.transform(viewportExtent.getCoordinateReferenceSystem(), true);
        }
      } catch (TransformException | FactoryException e) {
        throw new RuntimeException(e);
      }
      double[] points = new double[4];
      if (is2000To84) {
        // 手工转换：CGCS2000 到 WGS84
        // 手工转换步骤1：x与y轴平移转换
        double newMaxY = tileEnvViewport.getMaxX();
        double newMaxX = tileEnvViewport.getMaxY();
        double newMinY = tileEnvViewport.getMinX();
        double newMinX = tileEnvViewport.getMinY();
        // 手工转换步骤2：左右向反转
        double finalMaxY = newMaxY;
        double finalMaxX = newMinX;
        double finalMinY = newMinY;
        double finalMinX = newMaxX;
        // 数组顺序[x,y,x,y]
        points[0] = finalMaxX;
        points[1] = finalMaxY;
        points[2] = finalMinX;
        points[3] = finalMinY;
      } else {

        points[0] = tileEnvViewport.getMinX();
        points[1] = tileEnvViewport.getMaxY();
        points[2] = tileEnvViewport.getMaxX();
        points[3] = tileEnvViewport.getMinY();
      }

      worldToImageTransform.transform(points, 0, points, 0, 2);

      renderTile(tile, g2d, points);
    }
  }

}
